package org.example.spring.ioc.source.config;

import org.example.spring.ioc.source.factory.DefaultListableBeanFactory;
import org.example.spring.ioc.source.util.ReflectUtils;
import org.dom4j.Document;
import org.dom4j.Element;

import java.util.List;

/**
 * @ClassName XmlBeanDefinitionDocumentReader
 * @Description 解析document对象
 * @Author ihcy
 * @Date 2019/7/23 15:00
 * @Version 1.0
 **/
public class XmlBeanDefinitionDocumentReader {

    private DefaultListableBeanFactory beanFactory;

    public XmlBeanDefinitionDocumentReader(DefaultListableBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    /**
     * 将配置信息封装到BeanDefinition
     *
     * @param document
     */
    public void loadBeanDefinitions(Document document) {
        Element rootElement = document.getRootElement();
        List<Element> elements = rootElement.elements();
        for (Element element : elements) {
            String name = element.getName();
            if ("bean".equals(name)) {
                parseDefaultElement(element);
            } else {
                // 自定义标签
                parseCustomElement(element);
            }
        }
    }

    /**
     * 解析默认标签
     *
     * @param beanElement bean标签
     */
    private void parseDefaultElement(Element beanElement) {
        try {
            if (beanElement == null) {
                return;
            }
            // 获取id属性
            String id = beanElement.attributeValue("id");
            // 获取name属性
            String name = beanElement.attributeValue("name");
            // 获取class属性
            String clazz = beanElement.attributeValue("class");
            Class<?> clazzType = Class.forName(clazz);
            // 获取init-method属性
            String initMethod = beanElement.attributeValue("init-method");

            String beanName = id == null ? name : id;
            beanName = beanName == null ? clazzType.getSimpleName() : beanName;
            // 创建BeanDefinition对象
            BeanDefinition beanDefinition = new BeanDefinition(beanName,clazz);
            beanDefinition.setInitMethod(initMethod);

            // 获取property子标签集合
            List<Element> propertyElements = beanElement.elements("property");
            for (Element propertyElement : propertyElements) {
                parsePropertyElement(beanDefinition, propertyElement);
            }
            // TODO constructor-arg 标签

            // 注册BeanDefinition
            registerBeanDefinition(beanName,beanDefinition);

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }



    /***
     * 解析property子标签
     * @param beanDefinition
     * @param propertyElement
     */
    private void parsePropertyElement(BeanDefinition beanDefinition, Element propertyElement) {
        if (propertyElement == null) {
            return;
        }
        // 获取name属性
        String name = propertyElement.attributeValue("name");
        // 获取value属性
        String value = propertyElement.attributeValue("value");
        // 获取ref属性
        String ref = propertyElement.attributeValue("ref");
        // 如果value和ref都有值，则返回
        if (value != null && !"".equals(value) && ref != null && !"".equals(ref)) {
            return;
        }
         // PropertyValue就封装着一个property标签的信息
        PropertyValue pv = null;

        if (value != null && !"".equals(value)) {
            // 因为spring配置文件中的value是String类型，而对象中的属性值是各种各样的，所以需要存储类型
            TypedStringValue typeStringValue = new TypedStringValue(value);
            Class<?> targetType = ReflectUtils.getTypeByFieldName(beanDefinition.getBeanClassName(), name);
            typeStringValue.setTargetType(targetType);

            pv = new PropertyValue(name, typeStringValue);
            beanDefinition.addPropertyValue(pv);
        } else if (ref != null && !"".equals(ref)){
            RuntimeBeanReference reference = new RuntimeBeanReference(ref);
            pv = new PropertyValue(name, reference);
            beanDefinition.addPropertyValue(pv);
        } else {
            return;
        }
    }

    /**
     * 解析自定义标签
     *
     * @param element
     */
    private void parseCustomElement(Element element) {

    }

    /**
     * 注册BeanDefinition
     * @param beanName
     * @param beanDefinition
     */
    private void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        beanFactory.registerBeanDefinition(beanName,beanDefinition);
    }

}
